#include "seismicgrid.h"
#include "QtSerialization.h"

string SeismicGrid::m_objname = "SeismicGrid";
ExaFileObj SeismicGrid::m_file_obj = EXA_FILE_OBJ_SEISMICLANDMARKS;

SeismicGrid::SeismicGrid()
{
	m_d1 = -1;
	m_d2 = -1;
	m_d3 = -1;
	m_d4 = -1;
    m_tp_calc = LM_CALC_SITECOORD_LANDMARKSDB;

	m_isAlt = false;
	m_isChecked = false;
	m_isDat = false;
	m_isSolved = false;

	m_img_nfile = "";
	m_preview = false;
	// m_img_dir = "";
}

SeismicGrid::SeismicGrid(const SeismicGrid& g) :
    PKeyItem(g)
{
	site = g.site;
	P1 = g.P1; P2 = g.P2; P3 = g.P3; P4 = g.P4;
	m_d1 = m_d1; m_d2 = m_d2; m_d3 = m_d3; m_d4 = m_d4;
	m_tp_calc = g.m_tp_calc;
	   m_img_nfile =    g.m_img_nfile;
		 m_preview =      g.m_preview;

		   m_isAlt =        g.m_isAlt;
	m_isChecked = g.m_isChecked;
		   m_isDat =        g.m_isDat;
		m_isSolved =     g.m_isSolved;
}

SeismicGrid& SeismicGrid::operator = ( const SeismicGrid& g )
{
	site = g.site;
	P1 = g.P1; P2 = g.P2; P3 = g.P3; P4 = g.P4;
    m_d1 = g.m_d1; m_d2 = g.m_d2; m_d3 = g.m_d3; m_d4 = g.m_d4;
	m_tp_calc = g.m_tp_calc;
	m_img_nfile = g.m_img_nfile;
	m_preview = g.m_preview;

		   m_isAlt =        g.m_isAlt;
	m_isChecked = g.m_isChecked;
		   m_isDat =        g.m_isDat;
		m_isSolved =     g.m_isSolved;

    PKeyItem::operator = ( g );

	return *this;
}

void SeismicGrid::setKey(const PKeyItem& key)
{
    PKeyItem::operator = ( key );
}

void SeismicGrid::resetDistance(void)
{
	m_d1 = -1;
	m_d2 = -1;
	m_d3 = -1;
	m_d4 = -1;
}

void SeismicGrid::resetDistanceFromP1(void)
{
    m_d1 = -1;
}

void SeismicGrid::resetDistanceFromP2(void)
{
    m_d2 = -1;
}

void SeismicGrid::resetDistanceFromP3(void)
{
    m_d3 = -1;
}

void SeismicGrid::resetDistanceFromP4(void)
{
    m_d4 = -1;
}

double SeismicGrid::distanceFromP1(void) const { return m_d1; }
double SeismicGrid::distanceFromP2(void) const { return m_d2; }
double SeismicGrid::distanceFromP3(void) const { return m_d3; }
double SeismicGrid::distanceFromP4(void) const { return m_d4; }

void SeismicGrid::setDistanceFromP1(const double& d){ if (d>=0 || d==-1) {m_d1 = d;} ; }
void SeismicGrid::setDistanceFromP2(const double& d){ if (d>=0 || d==-1) {m_d2 = d;} ; }
void SeismicGrid::setDistanceFromP3(const double& d){ if (d>=0 || d==-1) {m_d3 = d;} ; }
void SeismicGrid::setDistanceFromP4(const double& d){ if (d>=0 || d==-1) {m_d4 = d;} ; }

void SeismicGrid::setImgName(const string& name)
{
	m_img_nfile = name;
}

/*
void SeismicGrid::setImgDir(const string& dir)
{
	m_img_dir = dir;
}
*/

void SeismicGrid::setImgPreview(const bool& b)
{
	m_preview = b;
}

bool SeismicGrid::getImgPreview(void) const
{
	return (m_preview);
}

string SeismicGrid::getImgName(void) const
{
	return(m_img_nfile);
}

/*
string SeismicGrid::getImgDir(void) const
{
	return(m_img_dir);
}
*/

void SeismicGrid::setTpCalc(const int& tp){
	switch (tp) {
        case LM_CALC_LANDMARKSID_DISTANCES :
            m_tp_calc = LM_CALC_LANDMARKSID_DISTANCES;
			break;
        case LM_CALC_SITECOORD_LANDMARKSID :
            m_tp_calc = LM_CALC_SITECOORD_LANDMARKSID;
			break;
        case LM_CALC_SITECOORD_LANDMARKSDB :
            m_tp_calc = LM_CALC_SITECOORD_LANDMARKSDB;
			break;
	}
}

void SeismicGrid::autoCalcDistance(void)
{
    int err;
    if (!site.isNull() && !P1.isNull())
    {
        qDebug("fromP1");
        setDistanceFromP1(site.dist(P1,err));
    }
    if (!site.isNull() && !P2.isNull())
    {
        qDebug("fromP2");
        setDistanceFromP2(site.dist(P2,err));
    }
    if (!site.isNull() && !P3.isNull())
    {
        qDebug("fromP3");
        setDistanceFromP3(site.dist(P3,err));
    }
    if (!site.isNull() && !P4.isNull())
    {
        qDebug("fromP4");
        setDistanceFromP4(site.dist(P4,err));
    }
}

void SeismicGrid::autoCalc(void)
{
    if ( TpCalc() == SeismicGrid::LM_CALC_SITECOORD_LANDMARKSID || TpCalc() == SeismicGrid::LM_CALC_SITECOORD_LANDMARKSDB )
	{
        autoCalcDistance(); // qDebug()<<"autocadistance";
	}
    bool controlled;
    controlled = solverCheck();
    if ( controlled == true )
        solve();
}

int SeismicGrid::TpCalc(void) const { return m_tp_calc; }

bool SeismicGrid::isSettingDistance(void) const {
	return ((m_d1!=-1) && (m_d2!=-1) && (m_d3!=-1) && (m_d4!=-1));
}

bool SeismicGrid::isSettingDistanceP1(void) const{ return m_d1!=-1 ; }
bool SeismicGrid::isSettingDistanceP2(void) const{ return m_d2!=-1 ; }
bool SeismicGrid::isSettingDistanceP3(void) const{ return m_d3!=-1 ; }
bool SeismicGrid::isSettingDistanceP4(void) const{ return m_d4!=-1 ; }

bool   SeismicGrid::solve(void) {
	if (!m_isChecked) {
		m_isSolved = false;
		   m_isAlt = true;
		   return false;
       }
	if (m_isAlt) {
		m_isSolved = false;
		   return false;
       } // qDebug()<<"solve";
	double d, agn, Fo, Tsc;
	d = 1/distanceFromP1()+1/distanceFromP2()+1/distanceFromP3()+1/distanceFromP4();
	agn = ( P1.get_SpecParam(SeismicPoint::TR30).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR30).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR30).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR30).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR30).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR30).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR30).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR30).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR30).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR30).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR30).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR30).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR30,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR50).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR50).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR50).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR50).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR50).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR50).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR50).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR50).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR50).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR50).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR50).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR50).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR50,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR72).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR72).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR72).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR72).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR72).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR72).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR72).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR72).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR72).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR72).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR72).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR72).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR72,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR101).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR101).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR101).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR101).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR101).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR101).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR101).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR101).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR101).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR101).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR101).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR101).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR101,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR140).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR140).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR140).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR140).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR140).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR140).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR140).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR140).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR140).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR140).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR140).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR140).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR140,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR201).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR201).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR201).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR201).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR201).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR201).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR201).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR201).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR201).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR201).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR201).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR201).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR201,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR475).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR475).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR475).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR475).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR475).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR475).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR475).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR475).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR475).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR475).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR475).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR475).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR475,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR975).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR975).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR975).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR975).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR975).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR975).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR975).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR975).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR975).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR975).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR975).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR975).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR975,SpecParam(agn,Fo,Tsc));

	agn = ( P1.get_SpecParam(SeismicPoint::TR2475).agn()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR2475).agn()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR2475).agn()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR2475).agn()/distanceFromP4())/d;
	 Fo = ( P1.get_SpecParam(SeismicPoint::TR2475).Fo()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR2475).Fo()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR2475).Fo()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR2475).Fo()/distanceFromP4())/d;
	Tsc = ( P1.get_SpecParam(SeismicPoint::TR2475).Tsc()/distanceFromP1()+
			P2.get_SpecParam(SeismicPoint::TR2475).Tsc()/distanceFromP2()+
			P3.get_SpecParam(SeismicPoint::TR2475).Tsc()/distanceFromP3()+
			P4.get_SpecParam(SeismicPoint::TR2475).Tsc()/distanceFromP4())/d;
		  site.set_SpecParam(SeismicPoint::TR2475,SpecParam(agn,Fo,Tsc));
	m_isSolved = true;
	m_isChecked = false;
	m_isAlt = false;
	return true;
}

bool SeismicGrid::isComplete(void) const {
	if (P1.isComplete() && P2.isComplete() && P3.isComplete() && P4.isComplete() && site.isComplete())
	{
		return (true);
	}
	return (false);
}

bool SeismicGrid::solverCheck(void) {
	m_isChecked = true;
	m_isSolved = false;
	// controllo che i punti abbiano i parametri completi
	if (
			!P1.isComplete() ||
			!P2.isComplete() ||
			!P3.isComplete() ||
			!P4.isComplete()
            )
	{
		m_isDat = false;
		m_isAlt = true;
		return false;
	}
	// controllo che le distanze siano settate
    if (!isSettingDistance())
    { // qDebug()<<"non setting sistance";
		m_isDat = false;
		m_isAlt = true;
		return false;
	}
	site.setEmpty();
	m_isDat = true;
	m_isAlt = false;
	return true;
}

void SeismicGrid::clearId(void)
{
    P1.setId(0);
    P2.setId(0);
    P3.setId(0);
    P4.setId(0);
}

void SeismicGrid::setEmpty(void)
{
    // site.setEmpty();
    //P1.setNull();
    P1.setEmpty();
    //P2.setNull();
    P2.setEmpty();
    //P3.setNull();
    P3.setEmpty();
    //P4.setNull();
    P4.setEmpty();
    // resetDistance();
}

void SeismicGrid::setNull(void)
{
    // site.setEmpty();
    P1.setNull();
    // P1.setEmpty();
    P2.setNull();
    // P2.setEmpty();
    P3.setNull();
    // P3.setEmpty();
    P4.setNull();
    // P4.setEmpty();
    // resetDistance();
}

void SeismicGrid::reportMake(const string& objname) const
{
    if (getReportCurrentStyle() == STYLE_VERBOSE)
    {
        PReport::resetReportOpt();
        PReport::setReportOpt("SUB",true);

        site.reportMake();
        moveReportInCache();

        addLineInReport("- CAPISALDO P1 -");
        P1.reportMake();
        moveReportInCache();

        addLineInReport("- CAPISALDO P2 -");
        P2.reportMake();
        moveReportInCache();

        addLineInReport("- CAPISALDO P3 -");
        P3.reportMake();
        moveReportInCache();

        addLineInReport("- CAPISALDO P4 -");
        P4.reportMake();
        moveReportInCache();

        moveCacheInBlock();

        PReport::setReportOpt("SUB",false);
    }
    else if (getReportCurrentStyle() == STYLE_COMPACT)
    {

    }
    PReport::reportMake(m_objname);
}

ExaFileObj SeismicGrid::fileObj ( void ) const
{
    return m_file_obj;
}

ExaFileErr SeismicGrid::fileOpen (const string& file_name)
{
    ExaFileErr file_err;
    file_err = fileControl(file_name,EXA_FILE_OM_READ_ONLY);

    if ( file_err == EXA_FILE_ERR_OK )
    {
        quint32 magic_obj = fileMagic();
        switch (magic_obj)
        {
            case EXA_MN_1_0_0_BIN_SLM:
            {
                /**************************************************/
                /*           FILE BINARIO SLS V 100               */
                /**************************************************/
                // apro intestazione dati binari
                QFile file(QSTR(file_name));
                if (file.open(QIODevice::ReadOnly))
                {
                    QDataStream in(&file);
                    in.setVersion(QDataStream::Qt_4_5);
                    quint32 magic_file, version_file;
                    in >> magic_file >> version_file;

                    // carico l'oggetto
                    in >> *this;
                }
                else
                {
                    return EXA_FILE_ERR_GENERIC;
                }
                /**************************************************/
            } break;
            default:
                return EXA_FILE_ERR_MN_UNKNOWN;
        }
    }
    fileReset();
    return file_err;
}

ExaFileErr SeismicGrid::fileSave (const string& file_name) const
{
    ExaFileErr file_err;
    file_err = fileControl(file_name,EXA_FILE_OM_WRITE_ONLY);

    if ( file_err == EXA_FILE_ERR_OK )
    {
        quint32 magic_obj = fileMagic();
        quint32 version_obj = fileVersion();

        switch (magic_obj)
        {
            case EXA_MN_1_0_0_BIN_SLM:
            {
                /**************************************************/
                /*           FILE BINARIO SLS V 100               */
                /**************************************************/
                // apro intestazione dati binari
                QFile file(QSTR(file_name));
                if (file.open(QIODevice::WriteOnly))
                {
                    // salvo i dati binari
                    QDataStream out(&file);
                    out.setVersion(QDataStream::Qt_4_5);
                    out << magic_obj << version_obj << *this ;
                }
                else
                {
                    return EXA_FILE_ERR_GENERIC;
                }
                /**************************************************/
            } break;
            default:
                return EXA_FILE_ERR_MN_UNKNOWN;
        }
    }
    fileReset();
    return file_err;
}

